package com.googlecode.yoohoo.xmppcore.protocol.translation;

import java.util.Stack;

import com.googlecode.yoohoo.xmppcore.utils.XmlUtils;

public class XmlWriter implements IXmlWriter {
	private StringBuilder builder;
	private Stack<String> elements;
	private boolean inStartElement;
	
	public XmlWriter() {
		builder = new StringBuilder();
		elements = new Stack<String>();
		inStartElement = false;
	}
	
	@Override
	public void writeAttribute(String localName, String value) {
		writeAttribute(null, localName, value);
	}

	@Override
	public void writeAttribute(String prefix, String localName, String value) {
		if (!inStartElement) {
			throw new IllegalStateException("Start element hasn't written. Please call writeStartElement() first.");
		}
		
		if (localName == null)
			throw new IllegalArgumentException("Null attribute local name.");
		
		if (value == null)
			throw new IllegalArgumentException("Null attribute value.");
		
		String attributeName = (prefix == null ? localName : prefix + ":" + localName);
		builder.append(' ').
			append(attributeName).
			append("='").
			append(value).
			append('\'');
	}

	@Override
	public void writeCharacters(String characters) {
		writeCharacters(characters, true);
	}

	@Override
	public void writeEndElement() {
		if (elements.isEmpty())
			throw new IllegalStateException("No element.");
		
		if (builder.length() == 0) {
			throw new IllegalStateException("Empty xml string");
		}
		
		String element = elements.pop();
		if (inStartElement) {
			builder.append("/>");
		} else {
			builder.append("</").
				append(element).
				append('>');
		}
		
		inStartElement = false;
	}

	@Override
	public void writeNamespace(String namespaceUri) {
		if (!inStartElement) {
			throw new IllegalStateException("Start element hasn't written. Please call writeStartElement() first.");
		}
		
		if (namespaceUri == null)
			throw new IllegalArgumentException("Null namespace URI.");
		
		builder.append(" xmlns='").append(namespaceUri).append('\'');
	}

	@Override
	public void writeStartElement(String localName) {
		writeStartElement(null, localName);
	}

	@Override
	public void writeStartElement(String prefix, String localName) {
		if (localName == null) {
			throw new IllegalArgumentException("Null element local name.");
		}
		
		if (inStartElement) {
			builder.append('>');
		}
		
		String element = (prefix == null ? localName : prefix + ":" + localName);
		builder.append('<').
			append(element);
		
		elements.push(element);
		inStartElement = true;
	}

	@Override
	public String toXml() {
		String xml = builder.toString();
		
		return xml;
	}

	@Override
	public void writePrefix(String prefix, String namespaceUri) {
		if (!inStartElement) {
			throw new IllegalStateException("Start element hasn't written. Please call writeStartElement() first.");
		}
		
		if (prefix == null)
			throw new IllegalArgumentException("Null prefix.");
		
		if (namespaceUri == null)
			throw new IllegalArgumentException("Null namespace URI.");
		
		builder.append(" xmlns:").
			append(prefix).
			append("='").
			append(namespaceUri).
			append("'");
	}

	@Override
	public void writeEmptyElement(String localName) {
		writeEmptyElement(null, localName);
	}

	@Override
	public void writeEmptyElement(String prefix, String localName) {
		writeStartElement(prefix, localName);
		writeEndElement();
	}

	@Override
	public void writeCharacters(String characters, boolean escape) {
		if (inStartElement) {
			builder.append('>');
		}
		
		if (characters != null) {
			if (escape) {
				builder.append(XmlUtils.escape(characters));
			} else {
				builder.append(characters);
			}
		}
		
		inStartElement = false;
	}
	
	@Override
	public String toString() {
		return toXml();
	}

}
